fix(snmp): walk only what the switch can safely answer - #26
Merged
Conversation
neo has never produced a metric. Two faults sat on top of each other, and
fixing either alone changed nothing observable.
The first was a missing pfSense rule: nothing permitted 10.0.99.20 to reach
10.7.7.2 on UDP/161, so every poll was dropped before it arrived. Fixed on the
firewall, not here.
The second is this. The switch returns ifSpecific (ifTable column 22) with a
zero-length value:
.1.3.6.1.2.1.2.2.1.22.26=
An OBJECT IDENTIFIER cannot be zero-length, so snmp-exporter rejects the entire
GETBULK response with "error parsing OID Value: invalid OID length" and the
scrape yields nothing. One malformed varbind cost all 22 metrics.
Listing columns 1-21 does not fix it. GETBULK returns the next N varbinds and
does not stop at a subtree boundary, so walking .21 overshoots into .22 and the
bad varbind comes back regardless. The last column walked has to be far enough
from .22 that max_repetitions cannot reach it.
So the walk is now the five columns something actually consumes — ifIndex,
ifDescr, ifOperStatus, ifInOctets, ifOutOctets. That is also the conservative
choice on its own merits: this switch was bricked once by a full walk and has
wedged since, so scrape volume is a safety property here. Measured cost is now
30 packets and 130 PDUs per scrape, 0 retries, 1.4s.
Drops 16 metrics (1791 -> 1775) deliberately: ifType, ifMtu, ifSpeed,
ifPhysAddress, ifAdminStatus, ifLastChange and the error/discard counters. None
is referenced by any rule or dashboard. Adding one back is a line, but anything
past .16 has to be checked against the ifSpecific overshoot first.
neo now scrapes clean: 26 ports, 19 up, all four SNMP targets up.
Closes #22
Co-Authored-By: Claude Opus 5 <[email protected]>
7 tasks
Gerrrt
added a commit
that referenced
this pull request
Aug 19, 2026
fix(snmp): walk only what the switch can safely answer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes
neoproduce metrics for the first time. Deployed and confirmed.What changed
The
mokerlinkwalk goes from the whole ifTable (1.3.6.1.2.1.2.2) to the fivecolumns anything actually consumes:
ifIndex,ifDescr,ifOperStatus,ifInOctets,ifOutOctets.Why
Two independent faults were stacked, which is why every single-cause fix
appeared to do nothing.
1. No firewall rule. Nothing permitted
10.0.99.20 → 10.7.7.2on UDP/161,so polls were dropped before arriving. Fixed on pfSense, outside this repo.
2. A malformed varbind. The switch returns
ifSpecific(ifTable column 22)with a zero-length value:
An OBJECT IDENTIFIER cannot be zero-length, so snmp-exporter rejects the whole
GETBULK response:
One bad varbind cost all 22 metrics.
Listing columns 1-21 does not fix it — that was tried and failed. GETBULK
returns the next N varbinds and does not stop at a subtree boundary, so walking
.21overshoots into.22and the bad varbind comes back anyway. The lastcolumn walked must be far enough from
.22thatmax_repetitionscannot reachit.
overrides: ifSpecific: ignoredoes not help either: it drops the metricfrom the config, but the reply still has to be decoded.
Walking less is also the conservative choice on its own merits. This switch was
bricked once by a full walk and has wedged since, so scrape volume is a safety
property here rather than an efficiency one.
Blast radius
snmp-exporter'smokerlinkmodule only. The other three modules arebyte-identical.
secrets/*.sops.yamlDeliberately drops 16 metrics (1791 → 1775), so
make snmp-generatewarnsabout metric loss — that warning is expected here. Dropped:
ifType,ifMtu,ifSpeed,ifPhysAddress,ifAdminStatus,ifLastChange,ifInUcastPkts,ifInNUcastPkts,ifInDiscards,ifInErrors,ifInUnknownProtos,ifOutUcastPkts,ifOutNUcastPkts,ifOutDiscards,ifOutErrors,ifOutQLen. None is referenced by any rule or dashboard (verified by grep overprometheus/rules/andgrafana/dashboards/).Verification
Deployed via
make render && make reload.Metrics arriving — 26 ports, 19 up:
Scrape cost, which is the number that matters for this device:
No exporter errors since the reload.
SnmpTargetUnreachableandInstanceDownfor
10.7.7.2have cleared.make validatepassesgenerator.yaml, beside the walk list)Known limitation
./scripts/snmp-verify.shstill reportsFAILforneo. It probessysDescr.0with a single GET, and this switch does not answer ad-hoc probesreliably even while serving the exporter's scrape cleanly at 0 retries — it
appears to throttle or accept only one SNMP conversation at a time. Not
investigated further on purpose, because characterising it means sending this
switch more SNMP than it has proven able to take.
The exporter scraping successfully is itself proof the community is correct, so
the rotation is verified by a different route. Filed separately rather than
worked around here.
Closes #22